﻿using System;
using System.Collections.Generic;
using System.Runtime.Remoting.Messaging;

namespace Sofire.AOP
{
    /// <summary>
    /// AOP 配置信息。
    /// </summary>
    public static class AOPSetting
    {
        /// <summary>
        /// 设置或获取一个值，指示 AOP 的启用状态。默认为 false，表示不启用 AOP。
        /// </summary>
        public static bool Enabled { get; set; }

        /// <summary>
        /// 设置或获取一个值，指示 AOP 在事件触发过程中，是否再次或多次引发事件。默认为 false，表示事件处理过程中，只触发一次。
        /// </summary>
        public static bool RaiseOnEvent { get; set; }

        ///// <summary>
        ///// 在“实例化对象”、“设置或获取字段”、“设置或获取属性”、“注册或注销事件”或“调用方法”时发生。
        ///// </summary>
        //public static event EnterInvokeEventHandler EnterInvoke;
        ///// <summary>
        ///// 在“实例化对象”、“设置或获取字段”、“设置或获取属性”、“注册或注销事件”或“调用方法”后发生。
        ///// </summary>
        //public static event LeaveInvokeEventHandler LeaveInvoke;

        private readonly static Dictionary<string, List<IAOPHandler>> RegisteredHandlers = new Dictionary<string, List<IAOPHandler>>();

        /// <summary>
        /// 将指定的 <see cref="Sofire.AOP.IAOPHandler"/> 注册到指定的实例类型中。
        /// </summary>
        /// <typeparam name="T">实例的类型。</typeparam>
        /// <param name="handler">AOP 处理器。</param>
        public static void RegisterHandler<T>(IAOPHandler handler)
        {
            RegisterHandler(typeof(T), handler);
        }

        /// <summary>
        /// 将指定的 <see cref="Sofire.AOP.IAOPHandler"/> 注册到指定的实例类型中。
        /// </summary>
        /// <param name="type">实例的类型。</param>
        /// <param name="handler">AOP 处理器。</param>
        public static void RegisterHandler(Type type, IAOPHandler handler)
        {
            if(type == null) throw new ArgumentNullException("type");
            if(handler == null) throw new ArgumentNullException("handler");

            List<IAOPHandler> hanlders;
            var qualifiedName = type.AssemblyQualifiedName;
            lock(RegisteredHandlers)
            {
                if(!RegisteredHandlers.TryGetValue(qualifiedName, out hanlders))
                {
                    hanlders = new List<IAOPHandler>();
                    RegisteredHandlers.Add(qualifiedName, hanlders);
                }
                lock(hanlders)
                {
                    hanlders.Add(handler);
                }
            }
        }

        /// <summary>
        /// 将注销指定的 <see cref="Sofire.AOP.IAOPHandler"/> 到指定的实例类型中。
        /// </summary>
        /// <typeparam name="T">实例的类型。</typeparam>
        /// <param name="handler">AOP 处理器。</param>
        public static void UnregisterHandler<T>(IAOPHandler handler)
        {
            UnregisterHandler(typeof(T), handler);
        }

        /// <summary>
        /// 将注销指定的 <see cref="Sofire.AOP.IAOPHandler"/> 到指定的实例类型中。
        /// </summary>
        /// <param name="type">实例的类型。</param>
        /// <param name="handler">AOP 处理器。</param>
        public static bool UnregisterHandler(Type type, IAOPHandler handler)
        {
            if(type == null) throw new ArgumentNullException("type");
            if(handler == null) throw new ArgumentNullException("handler");

            List<IAOPHandler> hanlders;
            var qualifiedName = type.AssemblyQualifiedName;
            lock(RegisteredHandlers)
            {
                if(RegisteredHandlers.TryGetValue(qualifiedName, out hanlders))
                {
                    lock(hanlders)
                    {
                        return hanlders.Remove(handler);
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 返回 true 表示允许访问，返回 false，表示拒绝访问
        /// </summary>
        internal static bool EnterInvoke(object instance, CallAction action, IMethodCallMessage call)
        {
            System.Diagnostics.Debug.Assert(call != null, "方法调用消息不得为空！");
            List<IAOPHandler> hanlders;
            var qualifiedName = call.TypeName;
            lock(RegisteredHandlers)
            {
                if(!RegisteredHandlers.TryGetValue(qualifiedName, out hanlders)) return false;
            }

            lock(hanlders)
            {
                var e = new EnterInvokeMessage(instance, action, call);
                foreach(var handler in hanlders)
                {
                    handler.EnterInvoke(e);
                }
                return !e.CallDenied;
            }
        }

        internal static void LeaveInvoke(object instance, CallAction action, IMethodCallMessage call, IMethodReturnMessage @return)
        {
            System.Diagnostics.Debug.Assert(@return != null, "方法返回消息不得为空！");

            List<IAOPHandler> hanlders;
            var qualifiedName = call.TypeName;
            lock(RegisteredHandlers)
            {
                if(!RegisteredHandlers.TryGetValue(qualifiedName, out hanlders)) return;
            }

            lock(hanlders)
            {
                var e = new LeaveInvokeMessage(instance, action, call, @return);
                foreach(var handler in hanlders)
                {
                    handler.LeaveInvoke(e);
                }
            }
        }

    }



    /// <summary>
    /// 一个 AOP 处理器。
    /// </summary>
    public interface IAOPHandler
    {
        /// <summary>
        /// 在“实例化对象”、“设置或获取字段”、“设置或获取属性”、“注册或注销事件”或“调用方法”时发生的消息。
        /// </summary>
        /// <param name="msg">消息参数。</param>
        void EnterInvoke(EnterInvokeMessage msg);
        /// <summary>
        /// 在“实例化对象”、“设置或获取字段”、“设置或获取属性”、“注册或注销事件”或“调用方法”后发生的消息。
        /// </summary>
        /// <param name="msg">消息参数。</param>
        void LeaveInvoke(LeaveInvokeMessage msg);
    }
}
